package org.footballmanager.pandafootball.system.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.footballmanager.pandafootball.common.annotation.SystemServiceLog;
import org.footballmanager.pandafootball.common.constants.Constants;
import org.footballmanager.pandafootball.common.job.AutoBfJob;
import org.footballmanager.pandafootball.common.job.CupBfJob;
import org.footballmanager.pandafootball.common.job.QuartzManager;
import org.footballmanager.pandafootball.common.util.DateUtils;
import org.footballmanager.pandafootball.system.domain.*;
import org.footballmanager.pandafootball.system.domain.enums.BFLX;
import org.footballmanager.pandafootball.system.domain.enums.BFZT;
import org.footballmanager.pandafootball.system.form.impl.FootCupbfSearchForm;
import org.footballmanager.pandafootball.system.mapper.FootCupbfMapper;
import org.footballmanager.pandafootball.system.service.*;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.*;

@Slf4j
@Service
public class FootCupbfServiceImpl extends ServiceImpl<FootCupbf> implements FootCupbfService {
    public static final double TOP16WIN = 15D;
    public static final double TOP16LOSE = 10D;

    public static final double TOP32WIN = 10D;
    public static final double TOP32LOSE = 8D;

    @Autowired
    private FootCupbfMapper footCupbfMapper;
    @Autowired
    private FootSjService footSjService;
    @Autowired
    private FootChipService footChipService;
    @Autowired
    private FootUserService footUserService;
    @Autowired
    private FootTeamService footTeamService;
    @Autowired
    private FootUserPersonService footUserPersonService;
    @Autowired
    private FootZnxService footZnxService;
    @Autowired
    private FootCupbmService footCupbmService;
    @Autowired
    private Scheduler scheduler;

    /**
     * 删除杯赛报分记录
     *
     * @param id      主键
     * @param request 请求
     * @return 是否成功
     */
    @Override
    @SystemServiceLog(description = "删除杯赛报分记录")
    public int delete(Serializable id, HttpServletRequest request) {
        FootCupbf t = this.get(id);
        log.info("删除杯赛报分:" + t.toString());
        if (t.getBfzt().equals(BFZT.HAVE)) {
            this.ffjj(t, false, request);
        }
        t.setBfzt(BFZT.NOT);
        t.setJq1(0);
        t.setJq2(0);
        return super.delete(id, request);
    }

    /**
     * 保存杯赛报分记录
     *
     * @param t       实体类
     * @param request 请求
     * @return 是否成功
     */
    @Override
    @SystemServiceLog(description = "保存杯赛报分记录")
    public int save(FootCupbf t, HttpServletRequest request) {
        footZnxService.sendZnx(t.getQd1(), t.getQd2(), "请确认" + t.getBflx().name() + "比赛结果",
                null, "/hy/footCupbf/view", request);
        return super.save(t, request);
    }

    @Override
    @SystemServiceLog(description = "更新非空杯赛报分记录")
    public int updateNotNull(FootCupbf footCupbf, HttpServletRequest request){
        Map<String, Object> mapParams = new HashMap<>();
        mapParams.put(Constants.ID, footCupbf.getId());
        Date date = DateUtils.addHours(new Date(), 2);

        //任务名称
        String name = UUID.randomUUID().toString();
        //任务所属分组
        String group = CupBfJob.class.getName();
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(DateUtils.getCron(date));
        //创建任务
        JobDetail jobDetail = JobBuilder.newJob(CupBfJob.class).withIdentity(name, group).build();
        jobDetail.getJobDataMap().put("paramMap", mapParams);
        //创建任务触发器
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(name, group).withSchedule(scheduleBuilder).build();
        //将触发器与任务绑定到调度器内
        try {
            scheduler.scheduleJob(jobDetail, trigger);
            if(scheduler.isShutdown()){
                scheduler.start();
            }
        } catch (SchedulerException e) {
            log.error(e.getMessage());
        }
        return super.updateNotNull(footCupbf, request);
    }

    /**
     * 确认杯赛报分信息
     *
     * @param bf      报分实体类
     * @param request 请求
     */
    @Override
    @Transactional
    @SystemServiceLog(description = "确认杯赛报分信息")
    public void makesure(FootCupbf bf, HttpServletRequest request) {
        footUserPersonService.autoDeletePerson(bf.getQd1(), request);
        footUserPersonService.autoDeletePerson(bf.getQd2(), request);
        bf.setBfzt(BFZT.HAVE);
        this.updateNotNull(bf, request);
        FootCupbm fc1 = footCupbmService.findCupbmByUserid(bf.getQd1());
        FootCupbm fc2 = footCupbmService.findCupbmByUserid(bf.getQd2());
        if (bf.getTime1()) {
            if (bf.getJq1() > bf.getJq2()) {
                fc1.setJj1(true);
            } else {
                fc2.setJj1(true);
            }
        } else if (bf.getTime2()) {
            if (bf.getJq1() > bf.getJq2()) {
                fc1.setJj2(true);
            } else {
                fc2.setJj2(true);
            }
        } else if (bf.getTime3()) {
            if (bf.getJq1() > bf.getJq2()) {
                fc1.setJj3(true);
            } else {
                fc2.setJj3(true);
            }
        } else if (bf.getTime4()) {
            if (bf.getJq1() > bf.getJq2()) {
                fc1.setJj4(true);
            } else {
                fc2.setJj4(true);
            }
        }
        footCupbmService.updateNotNull(fc1, request);
        footCupbmService.updateNotNull(fc2, request);
        //发放奖金
        this.ffjj(bf, true, request);
    }

    /**
     * 发放奖励
     *
     * @param bf      报分实体类
     * @param isadd   是否是奖励
     * @param request 请求
     */
    private void ffjj(FootCupbf bf, boolean isadd, HttpServletRequest request) {
        if (bf.getBflx().equals(BFLX.WINNER)) {
            //冠军杯站内信和财政变动
            processChangeMoney(bf, isadd, request, TOP16WIN, TOP16LOSE);
        } else {
            //联盟杯站内信和财政变动
            processChangeMoney(bf, isadd, request, TOP32WIN, TOP32LOSE);
        }
    }

    /**
     * 处理金额变动
     *
     * @param bf      报分实体类
     * @param isadd   是否是奖励
     * @param request 请求
     * @param win     胜场奖励金额
     * @param lose    败场奖励金额
     */
    private void processChangeMoney(FootCupbf bf, boolean isadd, HttpServletRequest request, Double win, Double lose) {
        FootTeam team1 = footTeamService.getTeamByUserid(bf.getQd1());
        FootTeam team2 = footTeamService.getTeamByUserid(bf.getQd2());
        if (bf.getJq1() > bf.getJq2()) {
            this.changeMoney(team1, win, bf.getBflx(), isadd, request);
            this.changeMoney(team2, lose, bf.getBflx(), isadd, request);
        } else {
            this.changeMoney(team1, lose, bf.getBflx(), isadd, request);
            this.changeMoney(team2, win, bf.getBflx(), isadd, request);
        }
    }

    /**
     * 改变金额
     *
     * @param team    队伍
     * @param money   金额
     * @param bflx    报分类型
     * @param isadd   是否是奖励
     * @param request 请求
     */
    private void changeMoney(FootTeam team, double money, BFLX bflx, boolean isadd, HttpServletRequest request) {
        String result = "已" + (isadd ? "确认" : "删除") + "比分,获得" + bflx.name() + "比赛奖金:" +
                new DecimalFormat(",###").format(money) + "PB,当前总资金为:" +
                new DecimalFormat(",###").format(team.getQdZzj()) + "PB";
        team.setYy(result);
        if (isadd) {
            team.setQdZzj(team.getQdZzj() + money);
        } else {
            team.setQdZzj(team.getQdZzj() - money);
        }
        footTeamService.updateNotNull(team, request);
    }

    /**
     * 根据次数和杯赛类型添加报分记录到数据库
     *
     * @param times   次数
     * @param type    类型
     * @param request 请求
     */
    @Override
    @SystemServiceLog(description = "根据次数和杯赛类型添加报分记录到数据库")
    public void createBf(int times, boolean type, HttpServletRequest request) {
        List<Long> tl = new ArrayList<>();
        List<FootCupbm> bmlist = footCupbmService.findByTypeAndSj(type, footSjService.getSj());
        if (bmlist == null || bmlist.isEmpty()) {
            return;
        }
        if (times == 1) {
            processTimes1(bmlist, tl, times, type, request);
        } else if (times == 2) {
            processTimes2(bmlist, tl, times, type, request);
        } else if (times == 3) {
            processTimes3(bmlist, tl, times, type, request);
        } else if (times == 4) {
            processTimes4(bmlist, tl, times, type, request);
        } else {
            processTimes5(type, request);
        }
    }

    /**
     * 处理次数5
     *
     * @param type    类型
     * @param request 请求
     */
    private void processTimes5(boolean type, HttpServletRequest request) {
        //确认第四次报分结果
        this.makesureLastTime("time4", request);
        this.reward(type, request);
    }

    /**
     * 处理次数4
     *
     * @param bmlist  报名列表
     * @param userIds 用户主键列表
     * @param times   次数
     * @param type    类型
     * @param request 请求
     */
    private void processTimes4(List<FootCupbm> bmlist, List<Long> userIds, int times, boolean type, HttpServletRequest request) {
        //确认第三次报分结果
        this.makesureLastTime("time3", request);
        for (int i = 0; i < bmlist.size(); i = i + 8) {
            boolean isAdd = false;
            for (int j = 0; j < 8; j++) {
                FootCupbm fc = bmlist.get(i + j);
                if (fc.getJj3()) {
                    userIds.add(fc.getUserId());
                    isAdd = true;
                }
            }
            if (!isAdd) {
                userIds.add(0L);
            }
        }
        this.addCupBf2Table(times, userIds, type, request);
    }

    /**
     * 处理次数3
     *
     * @param bmlist  报名列表
     * @param userIds 用户主键列表
     * @param times   次数
     * @param type    类型
     * @param request 请求
     */
    private void processTimes3(List<FootCupbm> bmlist, List<Long> userIds, int times, boolean type, HttpServletRequest request) {
        //确认第二次报分结果
        this.makesureLastTime("time2", request);
        for (int i = 0; i < bmlist.size(); i = i + 4) {
            boolean isAdd = false;
            for (int j = 0; j < 4; j++) {
                FootCupbm fc = bmlist.get(i + j);
                if (fc.getJj2()) {
                    userIds.add(fc.getUserId());
                    isAdd = true;
                }
            }
            if (!isAdd) {
                userIds.add(0L);
            }
        }
        this.addCupBf2Table(times, userIds, type, request);
    }

    /**
     * 处理次数2
     *
     * @param bmlist  报名列表
     * @param userIds 用户主键列表
     * @param times   次数
     * @param type    类型
     * @param request 请求
     */
    private void processTimes2(List<FootCupbm> bmlist, List<Long> userIds, int times, boolean type, HttpServletRequest request) {
        //确认第一次报分结果
        this.makesureLastTime("time1", request);
        for (int i = 0; i < bmlist.size(); i = i + 2) {
            boolean isAdd = false;
            for (int j = 0; j < 2; j++) {
                FootCupbm fc = bmlist.get(i + j);
                if (fc.getJj1()) {
                    userIds.add(fc.getUserId());
                    isAdd = true;
                }
            }
            if (!isAdd) {
                userIds.add(0L);
            }
        }
        this.addCupBf2Table(times, userIds, type, request);
    }

    /**
     * 处理次数1
     *
     * @param bmlist  报名列表
     * @param userIds 用户主键列表
     * @param times   次数
     * @param type    类型
     * @param request 请求
     */
    private void processTimes1(List<FootCupbm> bmlist, List<Long> userIds, int times, boolean type, HttpServletRequest request) {
        for (FootCupbm fc : bmlist) {
            if (null != fc.getUserId()) {
                userIds.add(fc.getUserId());
            } else {
                userIds.add(0L);
            }
        }
        this.addCupBf2Table(times, userIds, type, request);
    }

    /**
     * 奖励
     *
     * @param type    类型
     * @param request 请求
     */
    private void reward(boolean type, HttpServletRequest request) {
        FootCupbm bm = footCupbmService.getTop1(type);
        if (bm != null) {
            this.rewardTop1(bm, type, request);
        }
    }

    /**
     * 奖励top1
     *
     * @param bm      报名实体类
     * @param type    类型
     * @param request 请求
     */
    private void rewardTop1(FootCupbm bm, boolean type, HttpServletRequest request) {
        FootTeam team = footTeamService.getTeamByUserid(bm.getUserId());
        if (team != null) {
            double money = type ? 100D : 50D;
            team.setQdZzj(team.getQdZzj() + money);
            //获取碎片
            int numOfChip = type ? 5 : 3;
            String purpleNumber = String.valueOf(numOfChip);
            footChipService.randomGetChip(team.getUserId(), 4, numOfChip, request);
            numOfChip = type ? 2 : 1;
            String orangeNumber = String.valueOf(numOfChip);
            footChipService.randomGetChip(team.getUserId(), 5, numOfChip, request);

            String title = type ? "冠军杯" : "联盟杯";
            String result = "恭喜您,获得" + title + "冠军,发放奖金:" + new DecimalFormat(",###").format(money) +
                    "PB及紫色碎片" + purpleNumber + "个和橙色碎片" + orangeNumber + "个,当前总资金为:" +
                    new DecimalFormat(",###").format(team.getQdZzj()) + "PB";
            team.setYy(result);
            footTeamService.updateNotNull(team, request);
        }
    }

    /**
     * 如果上次报分没有结束，强制结束上次报分
     *
     * @param times   次数
     * @param request 请求
     */
    private void makesureLastTime(String times, HttpServletRequest request) {
        Map<String, Object> map = new HashMap<>();
        map.put("sj", footSjService.getSj());
        processTimes(times, map);
        map.put("bfzt", BFZT.NOT);
        List<FootCupbf> list = footCupbfMapper.findByMap(map);
        if (list != null && !list.isEmpty()) {
            for (FootCupbf fc : list) {
                fc.setBfzt(BFZT.HAVE);
                this.updateNotNull(fc, request);
            }
        }
    }

    /**
     * 根据次数和用户主键列表，添加新的报分记录到数据库
     *
     * @param times   次数
     * @param userIds 用户列表
     * @param type    类型
     * @param request 请求
     */
    private void addCupBf2Table(int times, List<Long> userIds, boolean type, HttpServletRequest request) {
        for (int i = 0; i < userIds.size(); i = i + 2) {
            FootCupbf bf = new FootCupbf();
            setQdInfo(bf, userIds, i);
            //立即晋级
            this.atOnceIn(bf, times, request);
            setTime(times, bf);
            if ((bf.getQd1() == 0 && bf.getQd2() != 0) || (bf.getQd1() != 0 && bf.getQd2() == 0)) {
                bf.setBfzt(BFZT.HAVE);
            } else {
                bf.setBfzt(BFZT.NOT);
            }
            bf.setSj(footSjService.getSj());
            if (type) {
                bf.setBflx(BFLX.WINNER);
            } else {
                bf.setBflx(BFLX.ALLIANCE);
            }
            super.save(bf, request);
        }
    }

    /**
     * 设置球队信息
     *
     * @param bf      报分记录
     * @param userIds 用户主键列表
     * @param i       第i个用户
     */
    private void setQdInfo(FootCupbf bf, List<Long> userIds, int i) {
        bf.setQd1(userIds.get(i));
        FootUser zhuuser = footUserService.get(userIds.get(i));
        if (zhuuser != null) {
            bf.setUserName1(zhuuser.getNike());
        } else {
            bf.setUserName1("");
        }
        if ((i + 1) < userIds.size()) {
            bf.setQd2(userIds.get(i + 1));
            FootUser keuser = footUserService.get(userIds.get(i + 1));
            if (keuser != null) {
                bf.setUserName2(keuser.getNike());
            } else {
                bf.setUserName2("");
            }
        } else {
            bf.setQd2(0L);
            bf.setUserName2("");
        }
    }

    /**
     * 设置次数
     *
     * @param times 次数
     * @param bf    报分实体类
     */
    private void setTime(int times, FootCupbf bf) {
        if (times == 1) {
            bf.setTime1(true);
        } else if (times == 2) {
            bf.setTime2(true);
        } else if (times == 3) {
            bf.setTime3(true);
        } else if (times == 4) {
            bf.setTime4(true);
        }
    }

    /**
     * 根据报分实体和次数立即晋级
     *
     * @param bf      报分实体类
     * @param times   次数
     * @param request 请求
     */
    @Override
    @SystemServiceLog(description = "根据报分实体和次数立即晋级")
    public void atOnceIn(FootCupbf bf, int times, HttpServletRequest request) {
        FootCupbm fc;
        if (bf.getQd1() == 0 && bf.getQd2() != 0) {
            fc = footCupbmService.findCupbmByUserid(bf.getQd2());
        } else if (bf.getQd1() != 0 && bf.getQd2() == 0) {
            fc = footCupbmService.findCupbmByUserid(bf.getQd1());
        } else {
            return;
        }
        if (times == 1) {
            fc.setJj1(true);
        } else if (times == 2) {
            fc.setJj2(true);
        } else if (times == 3) {
            fc.setJj3(true);
        } else if (times == 4) {
            fc.setJj4(true);
        }
        footUserPersonService.autoDeletePerson(bf.getQd1(), request);
        footUserPersonService.autoDeletePerson(bf.getQd2(), request);
        footCupbmService.updateNotNull(fc, request);
    }

    /**
     * 根据报分实体立即晋级
     *
     * @param bf      报分实体类
     * @param request 请求
     */
    @Override
    @SystemServiceLog(description = "根据报分实体立即晋级")
    public void atOnceIn(FootCupbf bf, HttpServletRequest request) {
        List<FootPerson> zhulist = footUserPersonService.findFootPersonByUserId(bf.getQd1(), request);
        List<FootPerson> kelist = footUserPersonService.findFootPersonByUserId(bf.getQd2(), request);
        FootCupbm fc;
        if (zhulist.size() < 18 && kelist.size() >= 18) {
            fc = footCupbmService.findCupbmByUserid(bf.getQd2());
        } else if (zhulist.size() >= 18 && kelist.size() < 18) {
            fc = footCupbmService.findCupbmByUserid(bf.getQd1());
        } else {
            return;
        }
        fc.setJj1(bf.getTime1());
        fc.setJj2(bf.getTime2());
        fc.setJj3(bf.getTime3());
        fc.setJj4(bf.getTime4());
        footUserPersonService.autoDeletePerson(bf.getQd1(), request);
        footUserPersonService.autoDeletePerson(bf.getQd2(), request);
        footCupbmService.updateNotNull(fc, request);
    }

    /**
     * 根据次数，赛季和比赛类型找报分记录
     *
     * @param times 次数
     * @param sjId  赛季主键
     * @param type  类型
     * @return 报分记录列表
     */
    @Override
    @SystemServiceLog(description = "根据次数，赛季和比赛类型找报分记录")
    public List<FootCupbf> findBf(String times, Long sjId, boolean type) {
        Map<String, Object> map = new HashMap<>();
        map.put("sj", sjId);
        map.put("bflx", type ? BFLX.WINNER : BFLX.ALLIANCE);
        processTimes(times, map);
        return footCupbfMapper.findByMap(map);
    }

    private void processTimes(String times, Map<String, Object> map) {
        if ("time1".equals(times)) {
            map.put("time1", true);
        } else if ("time2".equals(times)) {
            map.put("time2", true);
        } else if ("time3".equals(times)) {
            map.put("time3", true);
        } else {
            map.put("time4", true);
        }
    }

    /**
     * 查找第一场已报分的记录
     *
     * @param userId 用户主键
     * @return 报分记录
     */
    @Override
    @SystemServiceLog(description = "查找第一场已报分的记录")
    public FootCupbf findFirstBfResult(Long userId) {
        Map<String, Object> map = new HashMap<>();
        map.put("sj", footSjService.getSj());
        map.put("bfzt", BFZT.HAVE);
        map.put("bothQd", userId);
        List<FootCupbf> list = footCupbfMapper.findByMap(map);
        if (list != null && !list.isEmpty()) {
            return list.get(0);
        }
        return null;
    }

    @Override
    @SystemServiceLog(description = "根据用户主键查找杯赛报分记录")
    public FootCupbf findCupbfByUserId(Long userId) {
        Map<String, Object> map = new HashMap<>();
        map.put("sj", footSjService.getSj());
        map.put("bfzt", BFZT.NOT);
        map.put("bothQd", userId);
        map.put("bfUserId", null);
        List<FootCupbf> list = footCupbfMapper.findByMap(map);
        if (list != null && !list.isEmpty()) {
            return list.get(0);
        }
        return null;
    }

    /**
     * 根据用户主键查找可以确认报分的信息
     *
     * @param userId 用户主键
     * @return 报分记录
     */
    @Override
    @SystemServiceLog(description = "根据用户主键查找可以确认报分的信息")
    public FootCupbf findMakesureBfByUserid(Long userId) {
        Map<String, Object> map = new HashMap<>();
        map.put("sj", footSjService.getSj());
        map.put("bfzt", BFZT.NOT);
        map.put("bothQd", userId);
        map.put("bfUserId", userId);
        List<FootCupbf> list = footCupbfMapper.findByMap(map);
        if (list != null && !list.isEmpty()) {
            return list.get(0);
        }
        return null;
    }

    /**
     * 根据条件查找杯赛报分记录列表
     *
     * @param footCupbfSearchForm 条件
     * @return 列表
     */
    @Override
    @SystemServiceLog(description = "根据条件查找杯赛报分记录列表")
    public List<FootCupbf> findall(FootCupbfSearchForm footCupbfSearchForm) {
        return footCupbfMapper.findall(footCupbfSearchForm);
    }

    /**
     * 根据主键获取记录
     *
     * @param id 主键
     * @return 记录
     */
    @Override
    @SystemServiceLog(description = "根据杯赛报分主键查找杯赛报分记录")
    public FootCupbf get(Serializable id) {
        return footCupbfMapper.findById(id);
    }

    /**
     * 根据条件查找杯赛报分记录列表
     *
     * @param entityname          实体类名
     * @param map                 参数
     * @param footCupbfSearchForm 条件
     */
    @Override
    @SystemServiceLog(description = "根据条件查找杯赛报分记录列表")
    public void search(String entityname, Model map, FootCupbfSearchForm footCupbfSearchForm) {
        map.addAttribute(String.format(Constants.FORMNAME, entityname), footCupbfSearchForm);
        Page<FootCupbf> page = PageHelper.startPage(footCupbfSearchForm.getPageIndex(), footCupbfSearchForm.getPageSize());
        List<FootCupbf> list = this.findall(footCupbfSearchForm);
        map.addAttribute(Constants.PI, page.toPageInfo());
        map.addAttribute(String.format(Constants.LISTENTITY, entityname), list);
        map.addAttribute("title", footCupbfSearchForm.getBflx().name());
    }

    /**
     * 删除所有
     *
     * @param footCupbfSearchForm 条件
     * @param request             请求
     */
    @Override
    @SystemServiceLog(description = "根据条件删除所有杯赛报分记录列表")
    public void deleteAll(FootCupbfSearchForm footCupbfSearchForm, HttpServletRequest request) {
        if (footCupbfSearchForm.getSelectIds() != null) {
            String[] result = footCupbfSearchForm.getSelectIds().split(Constants.COMMA);
            for (String id : result) {
                this.delete(Long.parseLong(id), request);
            }
        }
    }

}
